package cn.xinfei.xdecision.engine.runner.executor.strategy.component;

import cn.xinfei.xdecision.common.model.component.ComponentVo;
import cn.xinfei.xdecision.common.model.component.guiderule.RuleInfo;
import cn.xinfei.xdecision.common.model.component.scriptrule.RuleScriptVersion;
import cn.xinfei.xdecision.common.service.component.guiderule.RuleVersionService;
import cn.xinfei.xdecision.common.service.component.scriptrule.RuleScriptVersionService;
import cn.xinfei.xdecision.common.utils.enums.enginex.ComponentTypeEnum;
import cn.xinfei.xdecision.common.utils.util.runner.jeval.EvaluationException;
import cn.xinfei.xdecision.engine.runner.context.XDecisionContext;
import cn.xinfei.xdecision.engine.runner.executor.ComponentHandler;
import cn.xinfei.xdecision.engine.runner.executor.handler.RuleComponentHandler;
import cn.xinfei.xdecision.engine.runner.executor.handler.RuleGroupNodeHandler;
import cn.xinfei.xdecision.engine.runner.executor.handler.RulePostProcessHandler;
import cn.xinfei.xdecision.engine.runner.executor.model.StateTransmitModel;
import cn.xinfei.xdecision.engine.runner.executor.strategy.EngineComponentRunner;
import cn.xinfei.xdecision.engine.runner.service.RuleNodeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Collections;

@Slf4j
@Service
public class ScriptRuleComponent extends ComplexRuleComponent {

    @Autowired
    private RuleNodeService ruleNodeService;

    @Resource
    private RuleGroupNodeHandler ruleGroupNodeHandler;

    @Resource
    private RuleComponentHandler ruleComponentHandler;

    @Resource
    private RulePostProcessHandler rulePostProcessHandler;

    @Resource
    private RuleScriptVersionService ruleScriptVersionService;

    @Autowired
    private RuleVersionService versionService;

    private static final String RULE_GROUP_CACHE_PRE = "rule_group_cache_pre_";


    @Override
    public String getServiceName() {
        return EngineComponentRunner.PRE + ComponentTypeEnum.SCRIPT_RULE_BASE.getType();
    }


    @Override
    public void before(ComponentHandler nodeHandler) {
        String componentCode = nodeHandler.getCode();
        ComponentVo componentVo = nodeHandler.getComponentVo();
        Long versionNo = componentVo.getVersionNo();
        RuleScriptVersion ruleVersion = ruleScriptVersionService.getVersionByVersionNo(componentCode, versionNo);
        Long versionId = ruleVersion.getId();
        componentVo.setVersionId(versionId);
        RuleInfo ruleInfo = ruleNodeService.getRuleFromVersionId(componentCode, versionNo, versionId);
        String ruleInfoCacheKey = RULE_GROUP_CACHE_PRE + componentCode;
        nodeHandler.put(ruleInfoCacheKey, ruleInfo);
        nodeHandler.put(RulePostProcessHandler.ACTION_CACHE_PRE + componentCode,
                rulePostProcessHandler.combineAction(Collections.singletonList(ruleInfo)));
    }

    @Override
    public StateTransmitModel runNode(ComponentHandler nodeHandler) throws EvaluationException {

        StateTransmitModel stateTransmitModel = XDecisionContext.getContext().getStateContext();
        ComponentVo componentVo = nodeHandler.getComponentVo();
        Long versionId = componentVo.getVersionId();
        String componentCode = nodeHandler.getComponentCode();
        Long versionNo = componentVo.getVersionNo();
        String ruleInfoCacheKey = RULE_GROUP_CACHE_PRE + componentCode;
        RuleInfo ruleInfo = (RuleInfo) nodeHandler.get(ruleInfoCacheKey);
        ruleGroupNodeHandler.executeScriptRule(stateTransmitModel, componentCode, ruleInfo);
        //nodeHandler提供了一个回调钩子，解决规则模块的特殊场景
//        rulePostProcessHandler.postProcess(nodeHandler, stateTransmitModel);//测试时不需要累计分数
        rulePostProcessHandler.processRejectCode(stateTransmitModel,Arrays.asList(ruleInfo));
        //处理动作配置类
        bizProcessorThreadPool.execute(() -> rulePostProcessHandler.actionPostProcess(nodeHandler, componentCode));

        return stateTransmitModel;
    }


}
